#include "MyWidget.h"

static const QString ACCESS_KEY = "<YOUR AK>"; 
static const QString SECRET_KEY = "<YOUR SK>";
static const QString IMAGE_REQUEST_URL = "<YOUR IMAGE_REQUEST_URL>";
static const QString TOKEN_REQUEST_URL = "<YOUR REQUEST TOKEN>";

static std::string GetParentDirectory(const std::string& path)
{
    std::size_t found = path.find_last_of("\\/");
    if (found != std::string::npos) {
        return path.substr(0, found);
    }
    return "";
}

static std::string GetProjectRootPath()
{
    std::string currentFile(__FILE__);
    std::string currentDir = GetParentDirectory(currentFile);
    std::string projectRootPath = GetParentDirectory(currentDir);
    return projectRootPath;
}

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
    resize(800, 600);
    m_menuButtonLayout = new QVBoxLayout;
    m_menuButtonLayout->setAlignment(Qt::AlignTop);
    m_menuTitle = new QLabel(this);
    m_menuTitle->setText("Menu");
    m_menuTitle->setAlignment(Qt::AlignCenter);

    m_imageRecognitionButton = new QPushButton("Image Recognition", this);
    m_imageRecognitionButton->setFixedSize(140, 30);
    m_menuButtonLayout->addWidget(m_menuTitle);
    m_menuButtonLayout->addWidget(m_imageRecognitionButton);
    m_menuWidget = new QWidget(this);
    m_menuWidget->setLayout(m_menuButtonLayout);

    QFrame* line = new QFrame(this);
    line->setFrameShape(QFrame::VLine);
    line->setFrameShadow(QFrame::Sunken);

    m_stackWidget = new QStackedWidget(this);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(m_menuWidget, 1);
    mainLayout->addWidget(line);
    mainLayout->addWidget(m_stackWidget, 4);

    setLayout(mainLayout);
    connect(m_imageRecognitionButton, &QPushButton::clicked, this, &MyWidget::ImageRecognition);
}

void MyWidget::ImageRecognition()
{
    m_imageLayout = new QVBoxLayout;
    m_imageWidget = new QWidget(this);
    m_imageText = new QLabel(this);
    m_imageText->setText("Preview");
    m_imageText->setAlignment(Qt::AlignCenter);
    m_imageLayout->addWidget(m_imageText);
    m_image = new QLabel(this);
    m_fileName = QFileDialog::getOpenFileName(this, "open image");
    QString rootPath = QString::fromStdString(GetProjectRootPath());
    QString defaultFile = rootPath + "/asserts/vat-invoice.png";
    m_fileName = !m_fileName.isEmpty() ? m_fileName : defaultFile;
    QPixmap pixmap(m_fileName);
    m_image->setText("图片预览");
    m_image->setPixmap(pixmap);
    m_image->setScaledContents(true);
    m_image->resize(pixmap.width(), pixmap.height());
    m_imageLayout->addWidget(m_image);
    QPushButton *recogButton = new QPushButton("Recognition", this);
    m_imageLayout->addWidget(recogButton);
    m_imageWidget->setLayout(m_imageLayout);
    m_stackWidget->addWidget(m_imageWidget);
    m_stackWidget->setCurrentWidget(m_imageWidget);
    connect(recogButton, &QPushButton::clicked, this, &MyWidget::ShowRecognitionResult);
    return;
}

void MyWidget::ShowRecognitionResult()
{
    QJsonDocument recogResult = GetImageRecognitionResult();
    std::vector<QString> result = ParseJson(recogResult);
    m_recogWidget = new QListWidget(this);
    for (const QString& value : result) {
        m_recogWidget->addItem(value);
    }
    m_stackWidget->addWidget(m_recogWidget);
    m_stackWidget->setCurrentWidget(m_recogWidget);
    return;
}


QJsonDocument MyWidget::GetImageRecognitionResult()
{
    QNetworkAccessManager manager;
    QNetworkRequest request;
    request.setUrl(QUrl(IMAGE_REQUEST_URL));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    m_token = GetToken();
    request.setRawHeader("X-Auth-Token", m_token);
    QJsonObject requestBody;
    requestBody["image"] = ImageToBase64(m_fileName);
    QJsonDocument jsonDocument(requestBody);
    QByteArray requestData = jsonDocument.toJson();
    QNetworkReply *reply = manager.post(request, requestData);
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    QJsonDocument jsonResponse;
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray responseData = reply->readAll();
        jsonResponse = QJsonDocument::fromJson(responseData);
    } else {
        qDebug() << "Error:" << reply->errorString();
    }

    reply->deleteLater();
    return jsonResponse;
}

static QJsonObject FillRequestBody()
{
    QJsonObject requestBody;
    QJsonObject authObject;
    QJsonObject identityObject;
    QJsonArray methodsArray;
    methodsArray.append("hw_ak_sk");
    QJsonObject akSkObject;
    QJsonObject accessObject;
    accessObject["key"] = ACCESS_KEY;
    QJsonObject secretObject;
    secretObject["key"] = SECRET_KEY;
    akSkObject["access"] = accessObject;
    akSkObject["secret"] = secretObject;
    identityObject["hw_ak_sk"] = akSkObject;
    identityObject["methods"] = methodsArray;

    authObject["identity"] = identityObject;
    QJsonObject scopeObject;
    QJsonObject projectObject;
    projectObject["name"] = "cn-north-4";
    scopeObject["project"] = projectObject;
    authObject["scope"] = scopeObject;
    requestBody["auth"] = authObject;
    return requestBody;
}

QByteArray MyWidget::GetToken()
{
    QNetworkAccessManager manager;
    QNetworkRequest request;
    request.setUrl(QUrl(TOKEN_REQUEST_URL));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject requestBody = FillRequestBody();
    QJsonDocument jsonDocument(requestBody);
    QByteArray requestData = jsonDocument.toJson();
    QNetworkReply *reply = manager.post(request, requestData);
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();
    QJsonDocument jsonResponse;
    if (reply->error() == QNetworkReply::NoError) {
        QVariant token = reply->rawHeader("X-Subject-Token");
        m_token = token.toByteArray();
    } else {
        qDebug() << "Error:" << reply->errorString();
    }
    reply->deleteLater();
    return m_token;
}

QString MyWidget::ImageToBase64(const QString& imagePath)
{
    QImage image(imagePath);
    QByteArray byteArray;
    QBuffer buffer(&byteArray);
    image.save(&buffer, "PNG");
    return QString(byteArray.toBase64());
}

std::vector<QString> MyWidget::ParseItemList(const QJsonArray& itemArray)
{
    std::vector<QString> result;
    for (const auto& itemValue : itemArray) {
        if (itemValue.isObject()) {
            QJsonObject itemObject = itemValue.toObject();
            for (auto item = itemObject.begin(); item != itemObject.end(); ++item) {
                result.push_back(item.value().toString());
            }
        }
    }    
    return result;
}

std::vector<QString> MyWidget::ParseJson(const QJsonDocument& response)
{
    std::vector<QString> result;
    if (!response.isNull() && response.isObject()) {
        QJsonObject jsonObject = response.object();
        qDebug() << "Response:" << jsonObject;
        QJsonObject resultObject = jsonObject["result"].toObject();
        for (auto it = resultObject.begin(); it != resultObject.end(); ++it) {
            if (it.key() == "item_list") {
                QJsonArray itemArray = it.value().toArray();
                std::vector<QString> itemArrayResult = ParseItemList(itemArray);
                result.insert(result.end(), itemArrayResult.begin(), itemArrayResult.end());
                continue;
            }
            result.push_back(it.value().toString());
        }
    }
    return result; 
}